//
// Created by Administrator on 2019/12/11.
//
#include <iostream>
#include <mutex>
#include <thread>
#include <atomic>
#include <functional>
#include <condition_variable>

using namespace std;
using namespace std::placeholders;

std::mutex mtx;
const int N = 100000000;
int num = 0;
atomic<int> anum(0);

void run()
{
    for (int i = 0; i < N; i++)
    {
        mtx.lock();
        num++;
        mtx.unlock();
    }
}

void runWithAutomic(){
    for (int i = 0; i < N; i++)
    {
        anum++;
    }
}

void runWithLockGuard(){
    //相当于在java里面syntronized，只对这个花括号里面的代码块起作用，出了花括号就会解锁
    std::lock_guard<std::mutex> lock(mtx);
    for (int i = 0; i < N; i++)
    {
        num++;
    }
}

void printCC(){
    std::lock_guard<std::mutex> lock(mtx);
    std::cout<<"hello thread"<<std::endl;
}

void printII(int a){
    std::cout<<"hello "<< a<< std::endl;
}

void startCount(){

    clock_t s = clock();

    thread t1(runWithLockGuard);
    thread t2(runWithLockGuard);
//    thread t1(runWithAutomic);
//    thread t2(runWithAutomic);
//    thread t1(run);
//    thread t2(run);
    t1.join();
    t2.join();

    clock_t e = clock();
//    cout << "num=" << anum << ",用时 " << e - s << " ms" << endl;
    cout << "num=" << num << ",用时 " << e - s << " ms" << endl;
}

void startThread(){
    auto n = std::thread::hardware_concurrency();
    std::cout << n << std::endl;

    std::thread ptt(printCC);
    std::thread ptt2(printII, 123);
    ptt.join();
    ptt2.join();
}

void startLambda(){
    thread t1([](const char* str){
        cout<<this_thread::get_id()<<endl;
        this_thread::sleep_for(chrono::seconds(1));
        cout<<str<<endl;
    }, "nihao");
    t1.join();
}

void testSynchronize(){

    mutex mx;
    std::condition_variable cv;
    thread B([&]()
             {
                 cout << "B begin\n" << endl;
                 unique_lock<mutex> lock(mx);
                 //std::condition_variable只能和std::unique_lock<std::mutex>一起工作；
                 //因为wait内部会自动对当前线程进行加锁，而std::lock_guard在构造时已经加锁了，因此会导致在wait时又加锁，且lock_guard只有在析构时才会解锁，会导致wait期间锁无法释放
                 cout << "B wait\n" << endl;
                 cv.wait(lock);
                 cout << "B wakeup\n" << endl;
             });
    thread A([&]()
             {
                 cout << "A begin\n" << endl;
                 this_thread::sleep_for(std::chrono::milliseconds(1000));
                 cout << "A notify B\n" << endl;
                 cv.notify_one();
             });
    B.join();
    A.join();
    system("pause");
}

/**条件唤醒*/
void testSynchronize2(){
    mutex mx;
    condition_variable cv;
    bool flag = false;
    thread B([&]()
             {
                 cout << "B begin\n" << endl;
                 unique_lock<mutex> lock(mx);
                 cout << "B wait\n" << endl;
                 cv.wait(lock, [&] {return flag; });
                 cout << "B wakeup\n" << endl;
                 return 0;
             });
    thread A([&]()
             {
                 cout << "A begin\n" << endl;
                 cout << "A sleep_for 10ms \n" << endl;
                 this_thread::sleep_for(std::chrono::milliseconds(10));
                 cout << "A notify B\n" << endl;
                 cv.notify_one(); // 此处唤醒 B 失败
                 this_thread::sleep_for(std::chrono::milliseconds(1000));
                 cout << "A set flag = true \n" << endl;
                 flag = true;
                 cv.notify_one(); // 唤醒 B 成功
                 return 0;
             });
//    B.join();
//    A.join();
}

void testNotify(){
    mutex mx;
    condition_variable cv;
    thread B([&]()
             {
                 cout << "B begin\n" << endl;
                 unique_lock<mutex> ul(mx);
                 cout << "B wait\n" << endl;
                 cv.wait(ul);
                 cout << "B wakeup\n" << endl;
                 return 0;
             });

//    this_thread::sleep_for(std::chrono::milliseconds(1000));
    thread A([&]()
             {
                 cout << "A begin\n" << endl;
                 unique_lock<mutex> ul(mx);
                 std::this_thread::sleep_for(std::chrono::milliseconds(2000));
                 cout << "A wait\n" << endl;
                 cv.notify_one();
                 cout << "A wakeup\n" << endl;
                 return 0;
             });
    B.join();
    A.join();
}